<!DOCTYPE html>
<meta charset="utf-8">
<html>
  <head>
    <meta name="viewport" content="width=device-width">
  </head>
  <body>
    <form action="about:blank">
      <input id="input_text" type="text" size="10"><br>
      <input id="input_password" type="password" size="10">
    </form>

    <script>
      var selectionChangeEventLog = "";
      var otherEventLog = "";
      var mutationObserver = new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {
          addEventLog(mutation.type, mutation.detail);
        });
      })

      var mutationConfig = { attributes: false, childList: false, characterData: true };

      function addOtherEventLog(type, detail) {
        if (otherEventLog.length > 0) {
          otherEventLog += ',';
        }
        if (detail == null) {
          otherEventLog += type;
        } else {
          otherEventLog += type + '(' + detail + ')';
        }
      }

      function addSelectionChangeEventLog(type, detail) {
        if (selectionChangeEventLog.length > 0) {
          selectionChangeEventLog += ',';
        }
        if (detail == null) {
          selectionChangeEventLog += type;
        } else {
          selectionChangeEventLog += type + '(' + detail + ')';
        }
      }

      // selectionchange event is queued, so it races with the other events.
      // crbug.com/628964
      function getEventLogs() {
        if (otherEventLog.length > 0 && selectionChangeEventLog.length > 0)
          return otherEventLog + ',' + selectionChangeEventLog;
        return otherEventLog + selectionChangeEventLog;
      }

      function clearEventLogs() {
        selectionChangeEventLog = '';
        otherEventLog = '';
      }

      function addEventListener(element, event_name) {
        element.addEventListener(event_name, function (e) { addOtherEventLog(event_name, e.data); });
      }

      function addKeyEventListener(element, event_name) {
        element.addEventListener(event_name, function (e) { addOtherEventLog(event_name, e.keyCode); });
      }

      function addSelectionEventListener(event_name) {
        // Note that listeners added to the element are not effective for now.
        document.addEventListener(event_name, function (e) { addSelectionChangeEventLog(event_name, e.data); });
      }

      function registerListenersAndObserver(element) {
        addKeyEventListener(element, "keydown");
        addKeyEventListener(element, "keypress");
        addKeyEventListener(element, "keyup");
        addEventListener(element, "compositionstart");
        addEventListener(element, "compositionupdate");
        addEventListener(element, "compositionend");
        addEventListener(element, "beforeedit");
        addEventListener(element, "edit");
        addEventListener(element, "select");
        addEventListener(element, "change");
        addEventListener(element, "input");
        mutationObserver.observe(element, mutationConfig);
      }

      var inputText = document.getElementById("input_text");
      var contenteditableEvent = document.getElementById("contenteditable_event");

      // SelectionEventListener should be outside registerListenersAndObserver() to avoid duplication.
      addSelectionEventListener("selectionchange");

      registerListenersAndObserver(inputText);
      registerListenersAndObserver(contenteditableEvent);
    </script>
  </body>
</html>
